package org.folio.rest.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.folio.rest.RestVerticle;
import org.folio.rest.impl.other.PartyLogSave;
import org.folio.rest.impl.other.PartyUtil;
import org.folio.rest.impl.util.DBName;
import org.folio.rest.impl.util.ParallelAsync;
import org.folio.rest.impl.util.ParallelResult;
import org.folio.rest.jaxrs.model.*;
import org.folio.rest.jaxrs.resource.PartyReaderCreditRecord;
import org.folio.rest.persist.PgUtil;
import org.folio.rest.persist.PostgresClient;
import org.folio.rest.persist.cql.CQLWrapper;
import org.folio.rest.tools.utils.ValidationHelper;
import org.folio.util.UuidUtil;

import javax.ws.rs.core.Response;
import java.util.*;
import java.util.stream.Collectors;

import static io.vertx.core.Future.succeededFuture;

public class PartyReaderCreditRecordImpl implements PartyReaderCreditRecord {
    private static final Logger logger = LoggerFactory.getLogger("mod-party");

    @Override
    public void getPartyReaderCreditRecord(String query, int offset, int limit, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        String sql = "";
        JSONObject obj = JSONUtil.parseObj(query);

        Object json = obj.get("punishmentRecordGroup");

        sql = " WHERE jsonb-> 'punishmentRecordGroup' @> '"+json.toString()+"'";

        Object readerInfo = obj.getOrDefault("readerInfo", "");
        if(readerInfo !=null && !"".equals(readerInfo))
        {
            sql = sql + " And jsonb-> 'readerInfo' @> '"+readerInfo.toString()+"'";
        }

        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);

        String finalSql = sql;
        pg.get(DBName.NOTIFY_TABLE_READER_CREDIT,
                ReaderCreditRecordGroup.class,new String[]{"*"},sql+" group by id ORDER BY lower(f_unaccent(jsonb -> 'metadata' ->> 'updatedDate')) DESC " + "LIMIT "+limit+" OFFSET "+offset,true,false,getReply->{
                    ReaderCreditRecordCollection readerCreditRecordCollection = new ReaderCreditRecordCollection();
                    if (getReply.failed()){
                        asyncResultHandler.handle(succeededFuture(GetPartyReaderCreditRecordResponse.respond200WithApplicationJson(readerCreditRecordCollection)));
                        return;
                    }
                    List<ReaderCreditRecordGroup> list = getReply.result().getResults();
                    list.forEach(a->{
                        List<PunishmentRecordGroup> userReaderCreditRecord = a.getPunishmentRecordGroup().stream().filter(b -> b.getStatus().equals("1")).collect(Collectors.toList());
                        a.setPunishmentRecordGroup(userReaderCreditRecord);
                    });
                    pg.select("select count(*) as total from "+okapiHeaders.get(RestVerticle.OKAPI_HEADER_TENANT)+"_mod_party.reader_credit "+ finalSql,reply->{
                        JsonObject jsonObject = reply.result().getRows().get(0);
                        String total = jsonObject.getMap().getOrDefault("total","0").toString();
                        readerCreditRecordCollection.setReaderCreditRecordGroup(list);
                        readerCreditRecordCollection.setTotalRecords(Integer.getInteger(total,0));
                        asyncResultHandler.handle(succeededFuture(GetPartyReaderCreditRecordResponse.respond200WithApplicationJson(readerCreditRecordCollection)));
                    });

        });

    }

    @Override
    public void postPartyReaderCreditRecord(String lang, ReaderCreditRecord entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        //此保存非真原创保存,而是将黑名单加入到某个用户的行为记录表中


        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);

        pg.getById(DBName.NOTIFY_TABLE_READER_CREDIT, entity.getId(), ReaderCreditRecord.class, reply -> {
            if (reply.succeeded()) {
                ReaderCreditRecord data = reply.result();
                List<PunishmentRecordGroup> list = data.getPunishmentRecordGroup();
                list.forEach(a -> {
                    a.setStatus("0");
                });
                List<PunishmentRecordGroup> addRecordList = entity.getPunishmentRecordGroup();
                if (addRecordList.size() > 1) {
                    Errors valErr = ValidationHelper.createValidationErrorMessage("size", String.valueOf(addRecordList.size()),
                            "保存失败! 提交的黑名单记录不能超过一条");
                    asyncResultHandler.handle(Future.succeededFuture(GetPartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond404WithTextPlain(valErr)));
                    return;
                }
                list.addAll(addRecordList);
                pg.update(DBName.NOTIFY_TABLE_READER_CREDIT, data, data.getId(), update -> {
                    if (update.succeeded()) {
                        asyncResultHandler.handle(Future.succeededFuture(PostPartyReaderCreditRecordResponse.respond201WithApplicationJson(entity, PostPartyReaderCreditRecordResponse.headersFor201())));
                        return;
                    } else {
                        ValidationHelper.handleError(update.cause(), asyncResultHandler);
                        return;
                    }
                });
            }
        });
    }

    @Override
    public void getPartyReaderCreditRecordModifyAndByIdAndRecordId(String id, String recordId, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        if (!UuidUtil.isUuid(id)) {
            Errors valErr = ValidationHelper.createValidationErrorMessage("id", id,
                    "获取失败! 请求的编号不正确!");
            asyncResultHandler.handle(Future.succeededFuture(GetPartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond404WithTextPlain(valErr)));
            return;
        }
        if (!UuidUtil.isUuid(recordId)) {
            Errors valErr = ValidationHelper.createValidationErrorMessage("recordId", recordId,
                    "获取失败! 请求的编号不正确!");
            asyncResultHandler.handle(Future.succeededFuture(GetPartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond404WithTextPlain(valErr)));
            return;
        }
        PgUtil.getById(DBName.NOTIFY_TABLE_READER_CREDIT,
                ReaderCreditRecord.class, id, okapiHeaders, vertxContext,
                GetPartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.class,
                asyncResultHandler
        );
    }

    @Override
    public void deletePartyReaderCreditRecordModifyAndByIdAndRecordId(String id, String recordId, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        if (!UuidUtil.isUuid(id)) {
            Errors valErr = ValidationHelper.createValidationErrorMessage("id", id,
                    "获取失败! 请求的编号不正确!");
            asyncResultHandler.handle(Future.succeededFuture(DeletePartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond404WithTextPlain(valErr)));
            return;
        }
        if (!UuidUtil.isUuid(recordId)) {
            Errors valErr = ValidationHelper.createValidationErrorMessage("recordId", recordId,
                    "获取失败! 请求的编号不正确!");
            asyncResultHandler.handle(Future.succeededFuture(DeletePartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond404WithTextPlain(valErr)));
            return;
        }
        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);

        pg.getById(DBName.NOTIFY_TABLE_READER_CREDIT, id, ReaderCreditRecord.class, reply -> {
            if (reply.succeeded()) {
                ReaderCreditRecord data = reply.result();
                List<PunishmentRecordGroup> list = data.getPunishmentRecordGroup();
                list.forEach(a -> {
                    if (a.getId().equals(recordId)) {
                        a.setStatus("0");
                        return;
                    }
                });
                pg.update(DBName.NOTIFY_TABLE_READER_CREDIT, data, data.getId(), update -> {
                    if (update.succeeded()) {
                        asyncResultHandler.handle(Future.succeededFuture(DeletePartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond204()));
                        return;
                    } else {
                        ValidationHelper.handleError(update.cause(), asyncResultHandler);
                        return;
                    }
                });
            }
        });
    }

    @Override
    public void putPartyReaderCreditRecordModifyAndByIdAndRecordId(String id, String recordId, String lang, ReaderCreditRecord entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        if (!UuidUtil.isUuid(id)) {
            Errors valErr = ValidationHelper.createValidationErrorMessage("id", id,
                    "获取失败! 请求的编号不正确!");
            asyncResultHandler.handle(Future.succeededFuture(DeletePartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond404WithTextPlain(valErr)));
            return;
        }
        if (!UuidUtil.isUuid(recordId)) {
            Errors valErr = ValidationHelper.createValidationErrorMessage("recordId", recordId,
                    "获取失败! 请求的编号不正确!");
            asyncResultHandler.handle(Future.succeededFuture(DeletePartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond404WithTextPlain(valErr)));
            return;
        }
        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);

        pg.getById(DBName.NOTIFY_TABLE_READER_CREDIT, id, ReaderCreditRecord.class, reply -> {
            if (reply.succeeded()) {
                ReaderCreditRecord data = reply.result();
                data.setMetadata(entity.getMetadata());
                List<PunishmentRecordGroup> list = data.getPunishmentRecordGroup();
                list = list.stream().filter(a -> !recordId.equals(a.getId())).collect(Collectors.toList());
                List<PunishmentRecordGroup> updateRecordeList = entity.getPunishmentRecordGroup();
                Optional<PunishmentRecordGroup> updateRecorde = updateRecordeList.stream().filter(a -> a.getId().equals(recordId)).findAny();
                if (updateRecorde.isPresent()) {
                    list.add(updateRecorde.get());
                    data.setPunishmentRecordGroup(list);
                    pg.update(DBName.NOTIFY_TABLE_READER_CREDIT, data, data.getId(), update -> {
                        if (update.succeeded()) {
                            asyncResultHandler.handle(Future.succeededFuture(PutPartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond204()));
                            PartyLogSave.saveLog("修改读者证号为【" + entity.getReaderInfo().getBarcode() + "】的黑名单记录", 3, entity.getMetadata(), entity.getOperator(), okapiHeaders, asyncResultHandler, pg);
                            return;
                        } else {
                            ValidationHelper.handleError(update.cause(), asyncResultHandler);
                            return;
                        }
                    });
                    return;
                } else {
                    Errors valErr = ValidationHelper.createValidationErrorMessage("record", recordId,
                            "更新失败! 无法找到对应编号的记录!");
                    asyncResultHandler.handle(Future.succeededFuture(PutPartyReaderCreditRecordModifyAndByIdAndRecordIdResponse.respond404WithTextPlain(valErr)));
                    return;
                }
            }
        });
    }

    @Override
    public void postPartyReaderCreditRecordAdminCommit(String lang, ReaderBlackList entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        ParallelAsync executor = new ParallelAsync();
        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);
        entity.getReaderInfoGroup().forEach(readerInfoGroup -> {
            executor.addAsyncTask(this.modifyReaderCreditRecord(pg, readerInfoGroup, entity));
        });
        executor.start();
        executor.setHandler(reply->{
                List<ParallelResult> list = reply.result();
                List<String> barcode = list.stream().map(a -> a.getKey()).collect(Collectors.toList());
                asyncResultHandler.handle(Future.succeededFuture(PostPartyReaderCreditRecordAdminCommitResponse.respond201WithApplicationJson(entity, PostPartyReaderCreditRecordAdminCommitResponse.headersFor201())));
                PartyLogSave.saveLog("添加读者证号为【" + barcode.toString() + "】的黑名单记录", 2, entity.getMetadata(), entity.getOperator(), okapiHeaders, asyncResultHandler, pg);
        });

    }

    public Future<ParallelResult> modifyReaderCreditRecord(PostgresClient pg, ReaderInfoGroup readerInfoGroup, ReaderBlackList entity) {
        Future<ParallelResult> future = Future.future();
        CQLWrapper cql = PartyUtil.CQLCreate("( readerInfo.barcode ==  *" + readerInfoGroup.getBarcode() + "* )", 1, 0, DBName.NOTIFY_TABLE_READER_CREDIT);
        ParallelResult parallelResult = new ParallelResult();
        parallelResult.setKey(readerInfoGroup.getBarcode());
        pg.get(DBName.NOTIFY_TABLE_READER_CREDIT, ReaderCreditRecordGroup.class, new String[]{"*"}, cql, true, false, queryReply -> {
            if (queryReply.succeeded()) {
                List<ReaderCreditRecordGroup> result = queryReply.result().getResults();
                ReaderCreditRecordGroup readerCreditRecord = null;
                PunishmentRecordGroup newPunishmentRecordGroup = new PunishmentRecordGroup();
                newPunishmentRecordGroup.setStatus("1");
                newPunishmentRecordGroup.setId(UUID.randomUUID().toString());
                newPunishmentRecordGroup.setCreateDate(DateUtil.formatDate(new Date()));
                newPunishmentRecordGroup.setFoulDescription(entity.getPunishmentRecord().getFoulDescription());
                newPunishmentRecordGroup.setPrisonTerm(entity.getPunishmentRecord().getPrisonTerm());
                newPunishmentRecordGroup.setPrisonTermDay(entity.getPunishmentRecord().getPrisonTermDay());

                if (result.size() == 1) {
                    readerCreditRecord = result.get(0);
                    readerCreditRecord.setMetadata(entity.getMetadata());
                    List<PunishmentRecordGroup> oldPunishmentRecordList = readerCreditRecord.getPunishmentRecordGroup();
                    List<ConductRecordGroup> oldConductRecordList = readerCreditRecord.getConductRecordGroup();
                    Optional<ConductRecordGroup> oldConductRecord = oldConductRecordList.stream().filter(a -> a.getRuleId().equals(entity.getRules().getId())).findAny();
                    if (oldConductRecord.isPresent()) {
                        oldConductRecordList.forEach(a -> {
                            if (a.getRuleId().equals(entity.getRules().getId())) {
                                newPunishmentRecordGroup.setConductId(a.getId());
                                newPunishmentRecordGroup.setRuleId(a.getRuleId());
                                a.setLeaveEarly(0);
                                a.setLeave(0);
                                a.setBeLate(0);
                                a.setAbsence(0);
                                return;
                            }
                        });

                    } else {
                        //添加新的行为记录
                        ConductRecordGroup conductRecordGroup = new ConductRecordGroup();
                        conductRecordGroup.setAbsence(0);
                        conductRecordGroup.setLeaveEarly(0);
                        conductRecordGroup.setLeave(0);
                        conductRecordGroup.setBeLate(0);
                        conductRecordGroup.setRuleId(entity.getRules().getId());
                        conductRecordGroup.setId(UUID.randomUUID().toString());
                        conductRecordGroup.setStatus("1");
                        conductRecordGroup.setCreateDate(conductRecordGroup.getCreateDate());
                        newPunishmentRecordGroup.setConductId(conductRecordGroup.getId());
                        newPunishmentRecordGroup.setRuleId(conductRecordGroup.getRuleId());
                        if (oldConductRecordList.size()>0){
                            oldConductRecordList.forEach(a->{
                                a.setStatus("0");
                            });
                        }
                        oldConductRecordList.add(conductRecordGroup);

                    }
                    if (oldPunishmentRecordList.size() > 0) {
                        oldPunishmentRecordList.forEach(b -> {
                            b.setStatus("0");
                        });
                    }
                    oldPunishmentRecordList.add(newPunishmentRecordGroup);
                    readerCreditRecord.setConductRecordGroup(oldConductRecordList);
                    readerCreditRecord.setPunishmentRecordGroup(oldPunishmentRecordList);

                    pg.update(DBName.NOTIFY_TABLE_READER_CREDIT, readerCreditRecord, readerCreditRecord.getId(), updateReply -> {
                        if (updateReply.succeeded()) {
                            parallelResult.setFlag(true);
                        } else {
                            parallelResult.setFlag(false);
                        }
                        future.complete(parallelResult);
                        return;
                    });

                } else {
                    ReaderCreditRecordGroup readerCreditRecordGroup = new ReaderCreditRecordGroup();
                    ReaderInfo readerInfo = new ReaderInfo();
                    readerInfo.setBarcode( readerInfoGroup.getBarcode());
                    readerInfo.setEmail( readerInfoGroup.getEmail());
                    readerInfo.setMobilePhone(readerInfoGroup.getMobilePhone());
                    readerInfo.setName(readerInfoGroup.getName());
                    readerCreditRecordGroup.setId(UUID.randomUUID().toString());
                    readerCreditRecordGroup.setCreateDate(DateUtil.formatDate(new Date()));
                    readerCreditRecordGroup.setStatus("1");

                    ConductRecordGroup conductRecordGroup = new ConductRecordGroup();
                    conductRecordGroup.setAbsence(0);
                    conductRecordGroup.setLeaveEarly(0);
                    conductRecordGroup.setLeave(0);
                    conductRecordGroup.setBeLate(0);
                    conductRecordGroup.setRuleId(entity.getRules().getId());
                    conductRecordGroup.setId(UUID.randomUUID().toString());
                    conductRecordGroup.setStatus("1");
                    conductRecordGroup.setCreateDate( DateUtil.date().toDateStr());

                    newPunishmentRecordGroup.setConductId(conductRecordGroup.getId());
                    newPunishmentRecordGroup.setRuleId(conductRecordGroup.getRuleId());

                    List<ConductRecordGroup> conductRecordGroups = new ArrayList<>();
                    conductRecordGroups.add(conductRecordGroup);


                    List<PunishmentRecordGroup> punishmentRecordGroups = new ArrayList<>();
                    punishmentRecordGroups.add(newPunishmentRecordGroup);

                    readerCreditRecordGroup.setConductRecordGroup(conductRecordGroups);
                    readerCreditRecordGroup.setPunishmentRecordGroup(punishmentRecordGroups);
                    readerCreditRecordGroup.setReaderInfo(readerInfo);
                    readerCreditRecordGroup.setMetadata(entity.getMetadata());
                    pg.save(DBName.NOTIFY_TABLE_READER_CREDIT,readerCreditRecordGroup.getId(),readerCreditRecordGroup,saveReply->{
                        if (saveReply.succeeded()){
                            parallelResult.setFlag(true);
                        } else {
                            parallelResult.setFlag(false);
                        }
                        future.complete(parallelResult);
                        return;
                    });

                }
            }else{
            parallelResult.setFlag(false);
            future.complete(parallelResult);
            return;
            }
        });
        return future;
    }

//    @Override
//    public void getPartyReaderCreditRecordModifyAndById(String id, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
//        PgUtil.getById(DBName.NOTIFY_TABLE_READER_CREDIT,
//                ReaderCreditRecordGroup.class,
//                id,
//                okapiHeaders,
//                vertxContext,
//                GetPartyReaderCreditRecordModifyAndByIdResponse.class,
//                asyncResultHandler
//            );
//    }
//
//    @Override
//    public void deletePartyReaderCreditRecordModifyAndById(String id, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
//             //此删除非真删除,而是将用户旧的黑名单记录冻结
//        if (!UuidUtil.isUuid(id)) {
//            Errors valErr = ValidationHelper.createValidationErrorMessage("id",id,
//                    "删除失败! 请求删除的编号不正确!");
//            asyncResultHandler.handle(Future.succeededFuture(DeletePartyReaderCreditRecordModifyAndByIdResponse.respond400WithTextPlain(valErr)));
//            return;
//        }
//        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);
//
////        pg.getById(DBName.NOTIFY_TABLE_READER_CREDIT,id,ReaderCreditRecord.class,reply->{
////            if (reply.succeeded()){
////                ReaderCreditRecord data = reply.result();
////                List<PunishmentRecordGroup> list = data.getPunishmentRecordGroup();
////                list.forEach(a->{
////                    if (a.getStatus().toString().equals("1")){
////
////                    }
////                });
////            }
////        });
//    }
//
//    @Override
//    public void putPartyReaderCreditRecordModifyAndById(String id, String lang, ReaderCreditRecord entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
//
//    }
}
